package com.github.defense.plugin.gray.configuration;

import com.github.defense.plugin.gray.GrayClientInitializer;
import com.github.defense.plugin.gray.choose.DefaultGrayServerChoose;
import com.github.defense.plugin.gray.choose.GrayServerChoose;
import com.github.defense.plugin.gray.context.DefaultRoutingHandler;
import com.github.defense.plugin.gray.context.GrayLocalContext;
import com.github.defense.plugin.gray.context.RoutingHandler;
import com.github.defense.plugin.gray.decision.DefaultGrayDecisionResolver;
import com.github.defense.plugin.gray.decision.GrayDecisionResolver;
import com.github.defense.plugin.gray.decision.factory.*;
import com.github.defense.plugin.gray.decision.predicate.DefaultPolicyPredicate;
import com.github.defense.plugin.gray.decision.predicate.PolicyPredicate;
import com.github.defense.plugin.gray.instance.DefaultGrayInstanceSorter;
import com.github.defense.plugin.gray.instance.GrayInstanceSorter;
import com.github.defense.plugin.gray.manager.DefaultGrayDecisionManager;
import com.github.defense.plugin.gray.manager.DefaultGrayManager;
import com.github.defense.plugin.gray.manager.GrayDecisionManager;
import com.github.defense.plugin.gray.manager.GrayManager;
import com.github.defense.plugin.gray.server.ServerExplainer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.validation.Validator;

import java.util.List;

/**
 * @Author: lettger
 * @Date: 2021/6/7 2:32 下午
 */
@Configuration
public class GrayClientAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public GrayManager manager() {
        return new DefaultGrayManager();
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(GrayLocalContext.class)
    public RoutingHandler routingHandler(GrayManager manager, GrayLocalContext localContext) {
        return new DefaultRoutingHandler(manager, localContext);
    }

    @Bean
    public GrayClientInitializer initializer() {
        return new GrayClientInitializer();
    }

    @Bean
    @ConditionalOnMissingBean
    public GrayDecisionResolver decisionResolver(List<GrayDecisionFactory> decisionFactories, ConversionService conversionService, Validator validator) {
        return new DefaultGrayDecisionResolver(decisionFactories, conversionService, validator);
    }

    @Configuration
    public static class GrayDecisionFactoryConfiguration {

        @Bean
        public GrayDecisionFactory headerGrayDecisionFactory() {
            return new HeaderGrayDecisionFactory();
        }

        @Bean
        public GrayDecisionFactory methodGrayDecisionFactory() {
            return new MethodGrayDecisionFactory();
        }

        @Bean
        public GrayDecisionFactory parameterGrayDecisionFactory() {
            return new ParameterGrayDecisionFactory();
        }

        @Bean
        public GrayDecisionFactory flowRateGrayDecisionFactory() {
            return new FlowRateGrayDecisionFactory();
        }

    }


    @Bean
    @ConditionalOnMissingBean
    public GrayServerChoose serverChoose(ServerExplainer serverExplainer, GrayInstanceSorter instanceSorter) {
        return new DefaultGrayServerChoose(serverExplainer, instanceSorter);
    }

    @Bean
    public PolicyPredicate policyPredicate() {
        return new DefaultPolicyPredicate();
    }

    @Bean
    @ConditionalOnMissingBean
    public GrayDecisionManager grayDecisionManager(GrayDecisionResolver decisionResolver) {
        return new DefaultGrayDecisionManager(decisionResolver);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(GrayLocalContext.class)
    public GrayInstanceSorter instanceSorter(GrayLocalContext localContext, PolicyPredicate predicate, GrayDecisionManager decisionManager) {
        return new DefaultGrayInstanceSorter(localContext, predicate, decisionManager);
    }
}
